package application;

import Base.ResourceTest;
import EntityBuilder.RenterBuilder;
import com.huawei.translate.api.ApplicationApi;
import com.huawei.translate.model.Application;
import com.huawei.translate.notification.service.EmailTemplateType;
import com.huawei.translate.notification.service.NotificationService;
import com.huawei.translate.vo.application.UpdateApplicationRequest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;

import static org.mockito.Matchers.isA;

@RunWith(SpringRunner.class)
public class When_process_application extends ResourceTest {

    @Autowired
    @Mock
    private NotificationService notificationService;

    @Autowired
    @InjectMocks
    private ApplicationApi applicationApi;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void should_return_not_found_when_app_key_not_exist() {
        ResponseEntity<Object> response = this.testRestTemplate.getForEntity("/api/user/helloWorld", Object.class);
        Assert.assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
    }

    @Test
    public void should_return_found_when_app_key_existing() {
        new RenterBuilder(renterRepository).WithAppKey("Existing").Build();
        ResponseEntity<Object> response = this.testRestTemplate.getForEntity("/api/user/Existing", Object.class);
        Assert.assertEquals(HttpStatus.FOUND, response.getStatusCode());
    }

    @Test
    public void should_create_renter_when_admin_approve_application() {
        Application application = CreateApplication();

        UpdateApplicationRequest request = new UpdateApplicationRequest();
        request.setAppKey("appKey");

        ResponseEntity<Object> response = this.testRestTemplate.postForEntity("/api/applications/"+application.getId()+"/approve",request,Object.class);

        application = applicationRepository.findById(application.getId());

        Assert.assertEquals(HttpStatus.CREATED,response.getStatusCode());
        Assert.assertNotNull(application.getRenter());
        Assert.assertEquals(request.getAppKey(),application.getRenter().getAppKey());
        Assert.assertEquals(application.getAppName(),application.getRenter().getAppName());
        Assert.assertNotNull(application.getRenter().getAppSecret());
        Assert.assertEquals(1, application.getStatus());
    }

    @Test
    public void should_send_approve_email_to_applicant_when_admin_approved() {
        Application application = CreateApplication();
        UpdateApplicationRequest request = new UpdateApplicationRequest();
        request.setAppKey("appKey");
        Mockito.doNothing().when(notificationService).send(isA(EmailTemplateType.class), isA(Application.class));

        this.testRestTemplate.postForEntity("/api/applications/"+application.getId()+"/approve",request,Object.class);

        Mockito.verify(notificationService).send(isA(EmailTemplateType.class),isA(Application.class));
    }

    @Test
    public void should_return_bad_request_when_update_request_invalid() {
        Application application = CreateApplication();

        UpdateApplicationRequest request = new UpdateApplicationRequest();

        ResponseEntity<Object> response = this.testRestTemplate.postForEntity("/api/applications/"+application.getId()+"/approve",request,Object.class);

        Assert.assertEquals(HttpStatus.BAD_REQUEST,response.getStatusCode());
    }

    @Test
    public void should_reject_application_when_send_reject_request() {
        Application application = CreateApplication();

        ResponseEntity<Object> response = this.testRestTemplate.postForEntity("/api/applications/"+application.getId()+"/reject",null,Object.class);

        application = applicationRepository.findById(application.getId());

        Assert.assertEquals(HttpStatus.OK,response.getStatusCode());
        Assert.assertEquals(-1,application.getStatus());

    }

    @Test
    public void should_send_reject_email_when_application_rejected() {

        Mockito.doNothing().when(notificationService).send(isA(EmailTemplateType.class), isA(Application.class));

        Application application = CreateApplication();

        this.testRestTemplate.postForEntity("/api/applications/"+application.getId()+"/reject",null,Object.class);

        Mockito.verify(notificationService).send(isA(EmailTemplateType.class),isA(Application.class));
    }

    @Test
    public void should_return_forbidden_when_app_key_existing() {
        Application application = CreateApplication();
        UpdateApplicationRequest request = new UpdateApplicationRequest();
        request.setAppKey("HelloWorld");

        approve(request);

        request.setAppKey("HelloWorld");

        ResponseEntity<Object> response = this.testRestTemplate.postForEntity("/api/applications/"+application.getId()+"/approve",request,Object.class);

        Assert.assertEquals(HttpStatus.FORBIDDEN,response.getStatusCode());
    }

    public void approve(UpdateApplicationRequest request){
        Application application = CreateApplication();
        this.testRestTemplate.postForEntity("/api/applications/"+application.getId()+"/approve",request,Object.class);
    }

    private Application CreateApplication() {
        Application application = new Application();
        application.setAppName("welink");
        application.setOnlineDate(new Date());
        application.setAccessCountPerSec("100");
        application.setLanguages("en;zh");
        application.setDescription("HelloWorld!!");
        application.setProductOwner("yyy");
        application.setPoEmail("po@huawei.com");
        application.setInterfacePerson("interface");
        application.setiPersonEmail("inter@163.com");
        applicationRepository.save(application);
        return application;
    }

}
